package com.lagou.ipersistence.reflection;

import com.lagou.ipersistence.reflection.factory.ObjectFactory;
import com.lagou.ipersistence.reflection.property.PropertyTokenizer;
import com.lagou.ipersistence.reflection.wrapper.BeanWrapper;
import com.lagou.ipersistence.reflection.wrapper.MapWrapper;
import com.lagou.ipersistence.reflection.wrapper.ObjectWrapper;
import com.lagou.ipersistence.reflection.wrapper.ObjectWrapperFactory;

import java.util.Map;

/**
 * @author Yan Jiahong
 * Created on 2020/11/22
 */
public class MetaObject {
    private final Object originObject;
    private final ObjectWrapper objectWrapper;
    private final ObjectFactory objectFactory;
    private final ObjectWrapperFactory objectWrapperFactory;
    private final ReflectorFactory reflectorFactory;
    
    public MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory,
                      ReflectorFactory reflectorFactory) {
        this.originObject = object;
        this.objectFactory = objectFactory;
        this.objectWrapperFactory = objectWrapperFactory;
        this.reflectorFactory = reflectorFactory;
        
        if (object instanceof ObjectWrapper) {
            this.objectWrapper = (ObjectWrapper) object;
        } else if (object instanceof Map) {
            this.objectWrapper = new MapWrapper(this, (Map<String, Object>) object);
        } else {
            this.objectWrapper = new BeanWrapper(this, object);
        }
    }
    
    public static MetaObject froObject(Object object, ObjectFactory objectFactory,
                                       ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
        if (object == null) {
            return SystemMetaObject.NULL_META_OBJECT;
        } else {
            return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
        }
    }
    
    public Object getOriginObject() {
        return originObject;
    }
    
    public ObjectWrapper getObjectWrapper() {
        return objectWrapper;
    }
    
    public ObjectFactory getObjectFactory() {
        return objectFactory;
    }
    
    public ObjectWrapperFactory getObjectWrapperFactory() {
        return objectWrapperFactory;
    }
    
    public ReflectorFactory getReflectorFactory() {
        return reflectorFactory;
    }
    
    public Object getValue(String name) {
        PropertyTokenizer tokenizer = new PropertyTokenizer(name);
        if (tokenizer.hasNext()) {
            MetaObject metaValue = metaObjectForProperty(name);
            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                return null;
            } else {
                return metaValue.getValue(tokenizer.getChildren());
            }
        } else {
            return objectWrapper.get(tokenizer);
        }
    }
    
    public MetaObject metaObjectForProperty(String name) {
        Object value = getValue(name);
        return MetaObject.froObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
    }
    
    public boolean hasSetter(String name) {
        return objectWrapper.hasSetter(name);
    }
    
    public Class<?> getSetterType(String name) {
        return objectWrapper.getSetterType(name);
    }
    
    public void setValue(String name, Object value) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        objectWrapper.set(prop, value);
    }
}
